#include "specialsselectmodel.h"


#include <classlevel.h>


SpecialsSelectModel::SpecialsSelectModel(QObject *parent) :
    QAbstractListModel(parent)
{
}

void SpecialsSelectModel::setCampaign(Campaign *campaign)
{
    if (m_campaign.data() == campaign)
    {
        return;
    }

    beginResetModel();
    m_specialAbilities = 0;
    m_campaign = campaign;

    if (!m_campaign.isNull())
    {
        m_specialAbilities = m_campaign->findChild<SpecialAbilities*>(QString(), Qt::FindDirectChildrenOnly);
    }
    endResetModel();
}

int SpecialsSelectModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)

    if (!ready())
    {
        return 0;
    }

    return m_specialAbilities->findChildren<const SpecialAbility*>(QString(), Qt::FindDirectChildrenOnly).count();
}

QVariant SpecialsSelectModel::data(const QModelIndex &index, int role) const
{
    if (!ready())
    {
        return QVariant();
    }

    if (!index.isValid())
    {
        return QVariant();
    }

    if (role != Qt::CheckStateRole && role != Qt::DisplayRole && role != Qt::EditRole)
    {
        return QVariant();
    }

    QList<const SpecialAbility*> specialAbilityList = m_specialAbilities->findChildren<const SpecialAbility*>(QString(), Qt::FindDirectChildrenOnly);
    if (index.row() < 0 || index.row() >= specialAbilityList.count())
    {
        return QVariant();
    }

    const SpecialAbility* specialAbility = specialAbilityList.at(index.row());
    if (role == Qt::DisplayRole || role == Qt::EditRole)
    {
        return specialAbility->name();
    }

    if (m_characterClass.isNull() || m_classLevel.isNull())
    {
        return QVariant();
    }

    foreach (const SpecialAbility* classSpecial, m_classLevel->findChildren<const SpecialAbility*>())
    {
        if (classSpecial->name() == specialAbility->name())
        {
            return Qt::Checked;
        }
    }

    return Qt::Unchecked;
}

bool SpecialsSelectModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (role != Qt::CheckStateRole && role != Qt::EditRole)
    {
        qDebug() << Q_FUNC_INFO << "Not check state role or edit role!";
        return false;
    }

    if (!ready())
    {
        qDebug() << Q_FUNC_INFO << "Not ready";
        return false;
    }

    if (!index.isValid())
    {
        qDebug() << Q_FUNC_INFO << "Invalid index";
        return false;
    }


    QList<SpecialAbility*> specialAbilityList = m_specialAbilities->findChildren<SpecialAbility*>(QString(), Qt::FindDirectChildrenOnly);
    if (index.row() < 0 || index.row() >= specialAbilityList.count())
    {
        return false;
    }

    SpecialAbility* specialAbility = specialAbilityList.at(index.row());
    if (!specialAbility)
    {
        return false;
    }

    if (role == Qt::EditRole)
    {
        QString name = value.toString();
        if (name.isEmpty())
        {
            return false;
        }
        specialAbility->setName(value.toString());
        return true;
    }

    if (role != Qt::CheckStateRole)
    {
        return false;
    }

    if (m_characterClass.isNull() || m_classLevel.isNull())
    {
        qDebug() << Q_FUNC_INFO << "Character class or class level not ready!";
    }


    int checkState = value.toInt();

    foreach (SpecialAbility* classSpecial, m_classLevel->findChildren<SpecialAbility*>())
    {
        if (classSpecial->name() != specialAbility->name())
        {
            continue;
        }

        if (checkState == Qt::Checked)
        {
            return false;
        }

        classSpecial->setParent(0);
        classSpecial->deleteLater();

        emit dataChanged(index, index);
        return true;

    }

    if (checkState == Qt::Unchecked)
    {
        return false;
    }

    SpecialAbility* classSpecial = qobject_cast<SpecialAbility*>(m_classLevel->newChild());
    classSpecial->setReferenceItem(specialAbility);

    emit dataChanged(index, index);

//    qDebug() << Q_FUNC_INFO << "Added class special:" << classSpecial->name() << "to" << m_characterClass->name() << "level" << m_level;
    return true;
}

bool SpecialsSelectModel::insertRows(int row, int count, const QModelIndex &parent)
{
    Q_UNUSED(parent)
    Q_UNUSED(count)

    if (!ready())
    {
        return false;
    }

    row = m_specialAbilities->findChildren<SpecialAbility*>(QString(), Qt::FindDirectChildrenOnly).count();
    beginInsertRows(QModelIndex(), row, row);
    m_specialAbilities->newChild(tr("New Special Ability"));
    endInsertRows();

    return true;
}

bool SpecialsSelectModel::removeRows(int row, int count, const QModelIndex &parent)
{
    Q_UNUSED(count)

    if (!ready() || parent.isValid())
    {
        return false;
    }

    QList<SpecialAbility*> specialsList = m_specialAbilities->findChildren<SpecialAbility*>(QString(), Qt::FindDirectChildrenOnly);
    if (row < 0 || row >= specialsList.count())
    {
        return false;
    }

    beginRemoveRows(parent, row, row);

    SpecialAbility* specialAbility = specialsList.at(row);
    specialAbility->setParent(0);
    specialAbility->deleteLater();

    endRemoveRows();
    return true;
}

Qt::ItemFlags SpecialsSelectModel::flags(const QModelIndex &index) const
{
    return QAbstractListModel::flags(index) | Qt::ItemIsUserCheckable | Qt::ItemIsEditable;
}


void SpecialsSelectModel::setCharacterClassLevel(const QString &name, int level)
{
    if (name.isEmpty())
    {
        emit layoutAboutToBeChanged();
        m_characterClass = 0;
        emit layoutChanged();
        return;
    }

    CharacterClasses* characterClasses = m_campaign->findChild<CharacterClasses*>(QString(), Qt::FindDirectChildrenOnly);
    if (!characterClasses)
    {
        qDebug() << Q_FUNC_INFO << "Failed to find character classes container!";
        return;
    }

    foreach (CharacterClass* characterClass, characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly))
    {
        if (characterClass->name() == name)
        {
            m_characterClass = characterClass;
            break;
        }
    }

    if (m_characterClass.isNull())
    {
        qDebug() << Q_FUNC_INFO << "Failed to find character class:" << name;
        return;
    }

    ClassLevels* classLevels = m_characterClass->findChild<ClassLevels*>(QString(), Qt::FindDirectChildrenOnly);
    QList<ClassLevel*> classLevelList = classLevels->findChildren<ClassLevel*>(QString(), Qt::FindDirectChildrenOnly);
    if (level >= 0 && level < classLevelList.count())
    {
        m_classLevel = classLevelList.at(level);
    }
    else
    {
        qDebug() << Q_FUNC_INFO << "Character class" << name << "does not have level" << level;
    }


    int rows = rowCount(QModelIndex());
    QModelIndex first = index(0, 0, QModelIndex());
    QModelIndex last = index(rows-1, 0, QModelIndex());

    QVector<int> roles;
    roles << Qt::CheckStateRole;

    emit dataChanged(first, last, roles);
}


bool SpecialsSelectModel::ready() const
{
    bool ret = (!m_campaign.isNull() && !m_specialAbilities.isNull());
    if (!ret)
    {
        qDebug() << Q_FUNC_INFO << "Not ready!";
    }

    return ret;
}

void SpecialsSelectModel::revert()
{
    emit layoutAboutToBeChanged();
    emit layoutChanged();
}
